package com.example.servicewallet.service.impl;

import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.injector.methods.SelectObjs;
import com.example.servicewallet.entity.TUser;
import com.example.servicewallet.entity.TWallet;
import com.example.servicewallet.exception.MyException;
import com.example.servicewallet.mapper.TWalletMapper;
import com.example.servicewallet.service.TUserService;
import com.example.servicewallet.service.TWalletService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.servicewallet.vo.*;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;


import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author admin
 * @since 2023-02-08
 */
@Service
public class TWalletServiceImpl extends ServiceImpl<TWalletMapper, TWallet> implements TWalletService {

    @Autowired
    TUserService userService;

    @Autowired
    private RedisTemplate redisTemplate;


    /**
     * 绑定钱包
     * 用户名、手机号、身份证号码、银行卡号、银行名称
     *
     * @param registerWalletVo
     */
    @Override
    public void bindWallet(RegisterWalletVo registerWalletVo) {
        String username = registerWalletVo.getUsername();
        String mobile = registerWalletVo.getMobile();
        Long idCard = registerWalletVo.getIdCard();
        Long bankId = registerWalletVo.getBankId();
        String bankName = registerWalletVo.getBankName();

        //非空判断
        if (StringUtils.isEmpty(username) || StringUtils.isEmpty(mobile)
                || StringUtils.isEmpty(idCard) || StringUtils.isEmpty(bankId)
                || StringUtils.isEmpty(bankName)) {
            throw new MyException(20001, "绑定钱包失败");
        }

        //判断手机号是否重复，表里面存在相同手机号不进行添加
        QueryWrapper<TWallet> wrapper = new QueryWrapper<>();
        wrapper.eq("mobile", mobile);
        Integer count = baseMapper.selectCount(wrapper);
        if (count > 0) {
            throw new MyException(20001, "注册失败");
        }

        // 根据用户手机号查询用户信息
        TUser tUser = userService.selectUserByMobile(mobile);
        String id = tUser.getId();

        TWallet wallet = new TWallet();
        wallet.setBankId(bankId);
        wallet.setBankName(bankName);
        wallet.setUsername(username);
        wallet.setIdCard(idCard);
        wallet.setMemberId(id);
        wallet.setMobile(mobile);
        wallet.setOperationType(0);
        wallet.setStatus(0);

        baseMapper.insert(wallet);
    }

    /**
     * 根据手机号查询到 身份证号码、用户名、用户id
     *
     * @param mobile
     * @return
     */
    @Override
    public TWallet selectWalletByMobile(String mobile) {
        QueryWrapper<TWallet> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("mobile", mobile).last("limit 1");
        TWallet wallet = baseMapper.selectOne(queryWrapper);
        return wallet;
    }

    /**
     * 向钱包中进行充值
     *
     * @param rechargeVo
     * @return
     */
    @Transactional
    @Override
    public Map<String, Object> rechargeWallet(RechargeVo rechargeVo) {
        Long bankId = rechargeVo.getBankId();
        String mobile = rechargeVo.getMobile();
        String bankName = rechargeVo.getBankName();
        BigDecimal operationMoney = rechargeVo.getOperationMoney();

        String token = getTokenFromRedis(mobile);
        if (StringUtils.isEmpty(token)) {
            throw new MyException(20001, "用户没有登录");
        }

        Map<String, String> walletInfo = getWalletInfo(mobile);
        String idC = walletInfo.get("idCard");
        Long idCard = Long.parseLong(idC);
        String memberId = walletInfo.get("memberId");
        String username = walletInfo.get("username");

        TWallet wallet = new TWallet();
        wallet.setMemberId(memberId);
        wallet.setUsername(username);
        wallet.setMobile(mobile);
        wallet.setIdCard(idCard);
        wallet.setStatus(0);
        wallet.setOperationMoney(operationMoney);
        wallet.setOperationType(1);
        wallet.setOperationTime(new Date());
        wallet.setBankName(bankName);
        wallet.setBankId(bankId);

        baseMapper.insert(wallet);

        Map<String, Object> map = new HashMap<>();
        map.put("msg", "充值成功");
        map.put("money", "充值金额：" + operationMoney.toString());
        return map;
    }

    /**
     * 查询充值总余额
     *
     * @param rechargeVo
     * @return
     */
    @Override
    public Map<String, Object> selectRechargeTotal(RechargeVo rechargeVo) {
        Long bankId = rechargeVo.getBankId();
        String mobile = rechargeVo.getMobile();
        String bankName = rechargeVo.getBankName();

        QueryWrapper<TWallet> wrapper = new QueryWrapper<>();
        wrapper.eq("bank_id", bankId).eq("mobile", mobile).eq("bank_name", bankName)
                .eq("operation_type", 1);
        wrapper.select("operation_money");
        List<Object> balances = baseMapper.selectObjs(wrapper);

        BigDecimal total = new BigDecimal("0.00");

        for (Object balance : balances) {
            String str = JSONObject.toJSONString(balance);
            if (!str.equals("null")) {
                Map<String, Object> m = JSONArray.parseObject(str);
                String money = m.get("operationMoney").toString();
                total = total.add(new BigDecimal(money));
            }
        }
        // TODO 写入充值操作日志文件中
        Map<String, Object> map = new HashMap<>();
        map.put("msg", "查询成功");
        map.put("total", "充值总余额为：" + total);
        map.put("money", total);

        return map;
    }

    /**
     * 查询消费总余额
     *
     * @param payWalletVo
     * @return
     */
    @Override
    public Map<String, Object> selectPaymentTotal(PayWalletVo payWalletVo) {
        String mobile = payWalletVo.getMobile();
        Long bankId = payWalletVo.getBankId();
        String bankName = payWalletVo.getBankName();
        QueryWrapper<TWallet> wrapper = new QueryWrapper<>();
        wrapper.eq("bank_id", bankId).eq("mobile", mobile).eq("bank_name", bankName)
                .eq("operation_type", 3);
        wrapper.select("operation_money");
        List<Object> balances = baseMapper.selectObjs(wrapper);

        BigDecimal total = new BigDecimal("0.00");

        for (Object balance : balances) {
            String str = JSONObject.toJSONString(balance);
            if (!str.equals("null")) {
                Map<String, Object> m = JSONArray.parseObject(str);
                String money = m.get("operationMoney").toString();
                total = total.add(new BigDecimal(money));
            }
        }

        // TODO 写入操作消费日志文件中
        Map<String, Object> map = new HashMap<>();
        map.put("msg", "查询成功");
        map.put("total", "消费总余额为：" + total);
        map.put("money", total);

        return map;
    }

    /**
     * 查询提现总余额
     *
     * @param withDrawVo
     * @return
     */
    @Override
    public Map<String, Object> selectWithDraw(WithDrawVo withDrawVo) {
        Long bankId = withDrawVo.getBankId();
        String bankName = withDrawVo.getBankName();
        String mobile = withDrawVo.getMobile();
        QueryWrapper<TWallet> wrapper = new QueryWrapper<>();
        wrapper.eq("bank_id", bankId).eq("mobile", mobile).eq("bank_name", bankName)
                .eq("operation_type", 2);
        wrapper.select("operation_money");
        List<Object> balances = baseMapper.selectObjs(wrapper);

        BigDecimal total = new BigDecimal("0.00");

        for (Object balance : balances) {
            String str = JSONObject.toJSONString(balance);
            if (!str.equals("null")) {
                Map<String, Object> m = JSONArray.parseObject(str);
                String money = m.get("operationMoney").toString();
                total = total.add(new BigDecimal(money));
            }
        }

        //TODO 写入操作提现日志文件中
        Map<String, Object> map = new HashMap<>();
        map.put("msg", "查询成功");
        map.put("total", "提现总余额为：" + total);
        map.put("money", total);

        return map;
    }

    /**
     * 查询退款总余额
     *
     * @param returnWalletVo
     * @return
     */
    @Override
    public Map<String, Object> selectReturn(ReturnWalletVo returnWalletVo) {
        Long bankId = returnWalletVo.getBankId();
        String bankName = returnWalletVo.getBankName();
        String mobile = returnWalletVo.getMobile();
        QueryWrapper<TWallet> wrapper = new QueryWrapper<>();
        wrapper.eq("bank_id", bankId).eq("mobile", mobile).eq("bank_name", bankName)
                .eq("operation_type", 4);
        wrapper.select("operation_money");
        List<Object> balances = baseMapper.selectObjs(wrapper);

        BigDecimal total = new BigDecimal("0.00");

        for (Object balance : balances) {
            String str = JSONObject.toJSONString(balance);
            if (!str.equals("null")) {
                Map<String, Object> m = JSONArray.parseObject(str);
                String money = m.get("operationMoney").toString();
                total = total.add(new BigDecimal(money));
            }
        }

        // 写入操作退款日志文件中
        Map<String, Object> map = new HashMap<>();
        map.put("msg", "查询成功");
        map.put("total", "退款总余额为：" + total);
        map.put("money", total);

        return map;
    }

    /**
     * 查询余额  手机号 + 银行卡 + 银行名称
     * 余额 = 充值总金额 - 提现金额 - 消费金额 + 退款余额   > 0
     *
     * @param balanceVo
     * @return
     */
    @Override
    public Map<String, Object> searchBalance(BalanceVo balanceVo) {
        Long bankId = balanceVo.getBankId();
        String mobile = balanceVo.getMobile();
        String bankName = balanceVo.getBankName();

        //非空判断
        if (StringUtils.isEmpty(bankId) || StringUtils.isEmpty(bankName)
                || StringUtils.isEmpty(mobile)) {
            throw new MyException(20001, "信息不能为空");
        }

        String token = getTokenFromRedis(mobile);

        if (StringUtils.isEmpty(token)) {
            throw new MyException(20001, "用户没有登录");
        }

        // 查询消费余额
        PayWalletVo payWalletVo = new PayWalletVo();
        BeanUtils.copyProperties(balanceVo, payWalletVo);
        Map<String, Object> pm = selectPaymentTotal(payWalletVo);
        Object op = pm.get("money");
        BigDecimal pmoney = new BigDecimal(op.toString());

        // 查询充值余额
        RechargeVo rechargeVo = new RechargeVo();
        BeanUtils.copyProperties(balanceVo, rechargeVo);
        Map<String, Object> rm = selectRechargeTotal(rechargeVo);
        Object or = rm.get("money");
        BigDecimal rmoney = new BigDecimal(or.toString());

        // 查询提现余额
        WithDrawVo withDrawVo = new WithDrawVo();
        BeanUtils.copyProperties(balanceVo, withDrawVo);
        Map<String, Object> wm = selectWithDraw(withDrawVo);
        Object ow = wm.get("money");
        BigDecimal wmoney = new BigDecimal(ow.toString());

        // 查询退款余额
        ReturnWalletVo returnWalletVo = new ReturnWalletVo();
        BeanUtils.copyProperties(balanceVo, returnWalletVo);
        Map<String, Object> rem = selectReturn(returnWalletVo);
        Object ore = rem.get("money");
        BigDecimal remoney = new BigDecimal(ore.toString());

        BigDecimal total = new BigDecimal("0.00");
        total = rmoney.subtract(pmoney).subtract(wmoney).add(remoney);
        Map<String, Object> map = new HashMap<>();
        map.put("msg", "查询成功");
        map.put("total", "余额为：" + total);
        map.put("money", total);
        return map;
    }

    /**
     * 消费金额   银行卡号、银行名称、手机号、消费金额
     *
     * @param payWalletVo
     * @return
     */
    @Transactional
    @Override
    public Map<String, Object> payWallet(PayWalletVo payWalletVo) {
        Long bankId = payWalletVo.getBankId();
        String mobile = payWalletVo.getMobile();
        String bankName = payWalletVo.getBankName();
        BigDecimal operationMoney = payWalletVo.getOperationMoney();

        //非空判断
        if (StringUtils.isEmpty(bankId) || StringUtils.isEmpty(bankName)
                || StringUtils.isEmpty(mobile) || StringUtils.isEmpty(operationMoney)) {
            throw new MyException(20001, "信息不能为空");
        }

        String token = getTokenFromRedis(mobile);

        if (StringUtils.isEmpty(token)) {
            throw new MyException(20001, "用户没有登录");
        }

        // TODO 判断余额是否大于0
        BalanceVo balanceVo = new BalanceVo();
        BeanUtils.copyProperties(payWalletVo,balanceVo);
        Map<String, Object> balance = searchBalance(balanceVo);
        Object o = balance.get("money");
        BigDecimal bal = new BigDecimal(o.toString());
        int flag = bal.compareTo(new BigDecimal("0.00"));
        if (flag < 0){
            throw new MyException(20001, "余额不足");
        }

        Map<String, String> walletInfo = getWalletInfo(mobile);
        String idC = walletInfo.get("idCard");
        Long idCard = Long.parseLong(idC);
        String memberId = walletInfo.get("memberId");
        String username = walletInfo.get("username");

        TWallet wallet = new TWallet();
        wallet.setMemberId(memberId);
        wallet.setUsername(username);
        wallet.setMobile(mobile);
        wallet.setIdCard(idCard);
        wallet.setStatus(0);
        wallet.setOperationMoney(operationMoney);
        wallet.setOperationType(3);
        wallet.setOperationTime(new Date());
        wallet.setBankName(bankName);
        wallet.setBankId(bankId);

        baseMapper.insert(wallet);

        // TODO 商家钱包进账相同的金额

        Map<String, Object> map = new HashMap<>();
        map.put("msg", "消费成功");
        map.put("total", "消费余额为：" + operationMoney);
        return map;
    }

    /**
     * 用户进行退款操作    将用户消费金额返回到账户中 商家金额减少
     *
     * @param returnWalletVo
     * @return
     */
    @Transactional
    @Override
    public Map<String, Object> returnWallet(ReturnWalletVo returnWalletVo) {
        String mobile = returnWalletVo.getMobile();
        BigDecimal operationMoney = returnWalletVo.getOperationMoney();
        Long bankId = returnWalletVo.getBankId();
        String bankName = returnWalletVo.getBankName();

        //非空判断
        if (StringUtils.isEmpty(bankId) || StringUtils.isEmpty(bankName)
                || StringUtils.isEmpty(mobile) || StringUtils.isEmpty(operationMoney)) {
            throw new MyException(20001, "信息不能为空");
        }

        String token = getTokenFromRedis(mobile);
        if (StringUtils.isEmpty(token)) {
            throw new MyException(20001, "用户没有登录");
        }

        // TODO 判断用户余额是否大于等于20
        BalanceVo balanceVo = new BalanceVo();
        BeanUtils.copyProperties(returnWalletVo,balanceVo);
        Map<String, Object> balance = searchBalance(balanceVo);
        Object o = balance.get("money");
        BigDecimal bal = new BigDecimal(o.toString());
        int flag = bal.compareTo(new BigDecimal("0.00"));
        if (flag < 0){
            throw new MyException(20001, "余额不足");
        }

        Map<String, String> walletInfo = getWalletInfo(mobile);
        String idC = walletInfo.get("idCard");
        Long idCard = Long.parseLong(idC);
        String memberId = walletInfo.get("memberId");
        String username = walletInfo.get("username");

        TWallet wallet = new TWallet();
        wallet.setMemberId(memberId);
        wallet.setUsername(username);
        wallet.setMobile(mobile);
        wallet.setIdCard(idCard);
        wallet.setStatus(0);
        wallet.setOperationMoney(operationMoney);
        wallet.setOperationType(4);
        wallet.setOperationTime(new Date());
        wallet.setBankName(bankName);
        wallet.setBankId(bankId);

        baseMapper.insert(wallet);
        Map<String, Object> map = new HashMap<>();

        map.put("msg", "退款成功");
        map.put("total", "退款金额为：" + operationMoney);

        // TODO 商家账户减少相同余额
        return map;
    }

    /**
     * 查询钱包明细
     * @param selectVo
     * @return
     */
    @Override
    public Map<String, Object> selectAll(SelectVo selectVo) {
        Long bankId = selectVo.getBankId();
        String bankName = selectVo.getBankName();
        String mobile = selectVo.getMobile();
        Date begin = selectVo.getBegin();
        Date end = selectVo.getEnd();

        if (StringUtils.isEmpty(bankId) || StringUtils.isEmpty(bankName) || StringUtils.isEmpty(mobile)) {
            throw new MyException(20001, "数据不能为空");
        }

        String token = getTokenFromRedis(mobile);
        if (StringUtils.isEmpty(token)) {
            throw new MyException(20001, "用户没有登录");
        }

        Map<String, Object> map = new HashMap<>();

        QueryWrapper<TWallet> wrapper = new QueryWrapper<>();
        if ((begin == null) && (end == null)) {
            wrapper.eq("bank_id",bankId).eq("bank_name",bankName).eq("mobile",mobile);
            List<TWallet> tWallets = baseMapper.selectList(wrapper);
            map.put("list",tWallets);
        }
        if ((begin != null) && (end == null)) {
            wrapper.eq("bank_id",bankId).eq("bank_name",bankName).eq("mobile",mobile)
                    .ge("operation_time", DateUtil.parse(begin.toString()).toJdkDate());
            List<TWallet> tWallets = baseMapper.selectList(wrapper);
            map.put("list",tWallets);
        }
        if ((begin == null) && (end != null)) {
            wrapper.eq("bank_id",bankId).eq("bank_name",bankName).eq("mobile",mobile)
                    .le("operation_time",DateUtil.parse(end.toString()).toJdkDate());
            List<TWallet> tWallets = baseMapper.selectList(wrapper);
            map.put("list",tWallets);
        }
        return map;
    }

    /**
     * 将从redis中取token 抽出作为一个方法
     *
     * @param mobile
     * @return
     */
    private String getTokenFromRedis(String mobile) {
        // 1. 根据手机号查询用户
        TUser tUser = userService.selectUserByMobile(mobile);
        String username = tUser.getUsername();
        //  2. 获取用户登录token
        String token = redisTemplate.opsForValue().get(username).toString();
        return token;
    }

    /**
     * 获取用户钱包基本信息
     */
    private Map<String, String> getWalletInfo(String mobile) {
        TWallet oldWallet = this.selectWalletByMobile(mobile);
        Long idCard = oldWallet.getIdCard();
        String username = oldWallet.getUsername();
        String memberId = oldWallet.getMemberId();

        Map<String, String> map = new HashMap<>();
        map.put("idCard", idCard.toString());
        map.put("username", username);
        map.put("memberId", memberId);

        return map;
    }
}
